/*
 * app_multislot.c
 *
 *  Created on: 2023年7月18日
 *      Author: zlw
 */

#include "app_multislot.h"
#include "btl_interface.h"
#include "btl_interface_storage.h"
#include "app_log.h"
#include "em_device.h"
#include "em_core.h"

void ds_device_init_nvic(void)
{
  for (IRQn_Type i = SVCall_IRQn; i < EXT_IRQ_COUNT; i++) {
    NVIC_SetPriority(i, CORE_INTERRUPT_DEFAULT_PRIORITY);
  }
}

/**
 * biref: 上电后 slot初始化，并擦除原有数据
 * 注意：在使用bootloader相关函数之前需要先初始化中断优先级，否则会报错
 * */
void app_bootloader_init(void)
{
  int32_t err;
  ds_device_init_nvic();
  err = bootloader_init();
  if(err != BOOTLOADER_OK) {
      DS_app_log_error("erase slot err = %ld\r\n", err);
  }
  if(get_slot_info() == BOOTLOADER_OK) {
      erase_slot_if_needed();
  }
}

/**
 * biref: 获取slot信息
 * */
int32_t get_slot_info(void)
{
  int32_t err;
  BootloaderStorageSlot_t slotInfo;

  err = bootloader_getStorageSlotInfo(SLOT_ID, &slotInfo);
  DS_app_log_info("slot info addr = 0x%lx \r\n", slotInfo.address);
  DS_app_log_info("slot info size = %ld \r\n", slotInfo.length);
  return err;
}

/**
 * biref: 对slot分区数据进行校验
 * */
int32_t verify_application(void)
{
  int32_t err;
  err = bootloader_verifyImage(SLOT_ID, NULL);

  return err;
}

/**
 * biref: 擦除slot分区数据
 * */
void erase_slot_if_needed(void)
{
  uint32_t offset = 0, num_blocks = 0, i = 0;
  uint8_t buffer[256];
  bool dirty = false;
  int32_t err = BOOTLOADER_OK;

  /* check the download area content by reading it in 256-byte blocks */
  BootloaderStorageSlot_t slotInfo;

  err = bootloader_getStorageSlotInfo(SLOT_ID, &slotInfo);
  num_blocks = slotInfo.length / 256;

  while ((dirty == 0) && (offset < 256 * num_blocks) && (err == BOOTLOADER_OK))
  {
    err = bootloader_readStorage(0, offset, buffer, 256);
    if (err == BOOTLOADER_OK) {
      i = 0;
      while (i < 256)
      {
        if (buffer[i++] != 0xFF) {
          dirty = true;
          break;
        }
      }
      offset += 256;
    }
  }

  if (err != BOOTLOADER_OK) {
      DS_app_log_error("error reading flash! %lx\r\n", err);
  } else if (dirty) {
      DS_app_func_tm_in();
      bootloader_eraseStorageSlot(0);
      DS_app_func_tm_end("erase");
  } else {
      DS_app_log_error("download area is empty\r\n");
  }

  return;
}

/**
 * biref: 从slot分区读取数据
 * */
void read_data_from_slot(uint32_t offset, uint8_t *buffer, size_t length)
{
  int32_t err = bootloader_readStorage(SLOT_ID, offset, buffer, length);
  if(err != BOOTLOADER_OK) {
      DS_app_log_error("read data err = %ld\r\n", err);
  }
}

/**
 * biref: 将数据写入slot分区 buffer 四字节对齐
 * */
void write_data_to_slot(uint32_t offset, uint8_t *buffer, size_t length)
{
  int32_t err = BOOTLOADER_OK;

  err = bootloader_writeStorage(SLOT_ID, offset, buffer, length);
  if(err != BOOTLOADER_OK) {
      DS_app_log_error("write data err = %ld\r\n", err);
  }
}

/**
 * biref: 设置slot分区并运行新程序
 * */
void app_install_and_reboot(void)
{
  bootloader_setImageToBootload(SLOT_ID);
  bootloader_rebootAndInstall();
}
